How to solve a problem with a SQL server session state:
"Unable to serialize the session state in 'StateServer' and 'SQLServer'mode. In 'StateServer' and 'SQLServer' mode, ASP.NET will serialize the session state objects, and as the result non-serializable objects".
The possible scenarios that can cause this problem are described in detail below, as well as the problem solutions to these scenarios.
Scenario 1
1) Configure a SQL server session.
2) Create an AlertMessage class inherited from Command class with the following methods:
class AlertMessage : Command
{
public override void Execute(CommandContext context)
{
Context.ClientPage.Start(this, "Pipeline");
}
protected virtual void Pipeline(ClientPipelineArgs args)
{
if (!args.IsPostBack)
{
Context.ClientPage.ClientResponse.Alert("Alert");
args.WaitForPostBack();
}
}
}
3) Create an application with one button. The handler for the button click event has the following code:
public class TestForm : ApplicationForm
{
protected Button TestButton;
protected override void OnLoad(System.EventArgs e)
{
base.OnLoad(e);
TestButton.OnClick += TestButton_OnClick;
}
void TestButton_OnClick(object sender, System.EventArgs e)
{
CommandContext context = new CommandContext();
AlertMessage n = new AlertMessage();
n.Execute(context);
}
}
4) Clicking the button throws an exception: “Unable to serialize the session state in 'StateServer' and 'SQLServer'mode. In 'StateServer' and 'SQLServer' mode, ASP.NET will serialize the session state objects, and as the result non-serializable objects”.
Problem solution:
Mark your AlertMessage command class as [Serializable].
Scenario 2
1) Add any method to your TestForm class (e.g TestMethod)
public void TestMethod()
{
…
}
2) Change the AlertMessage class:
public delegate void ExecuteCallback(string id);
[Serializable]
public class AlertMessage : Create
{
public ExecuteCallback callback;
public override void Execute(CommandContext context)
{
Context.ClientPage.Start(this, "Pipeline");
}
public AlertMessage (ExecuteCallback callback)
{
this.callback = callback;
}
protected void Pipeline (ClientPipelineArgs args)
{
if (!args.IsPostBack)
{
Context.ClientPage.ClientResponse.Alert("Alert");
args.WaitForPostBack();
}
}
}
3) Modify the handler for the button click event as follows:
void TestButton_OnClick(object sender, System.EventArgs e)
{
CommandContext context = new CommandContext();
CreateItemTest createCommand = new CreateItemTest(delegate
{
OnRedrow();
Context.ClientPage.ClientResponse.Redraw();
});
createCommand.Execute(context);
}
4) Clicking the button throws an exception: “Unable to serialize the session state in 'StateServer' and 'SQLServer'mode. In 'StateServer' and 'SQLServer' mode, ASP.NET will serialize the session state objects, and as the result non-serializable objects”.
Problem solution:
The anonymous method here invokes the instance method of the form class. Obviously, when serializing a delegate to this method (as a part of the AlertMessage object), .NET will try to serialize the form object. It looks like anonymous methods won't "just work" when you deal with UI pipelines; you always have to make sure that the declaring class is [Serializable].
There are two possible solutions here:
- fall back on usual methods and declare that a static method should be used as the pipeline callback
- make a nested class with all the necessary data for the callback, mark it [Serializable] and move the callback to this class.